
`include "defines.v"

//----------------------------------------------------------------
//Module Name : id_stage.v
//Description of module:
//instration decode 
//----------------------------------------------------------------
//Designer:	Tang Pengyu
//Date: 2021/07/14	  
//----------------------------------------------------------------

/* verilator lint_off UNUSED */
/* verilator lint_off UNDRIVEN */
module id_stage(
  input		rst,
  input	[`INST_LEN-1:0]	inst,					//32 bit inst code
  input	[`REG_DATA_LEN-1:0]	rs1_data,			//op1 in rs1
  input	[`REG_DATA_LEN-1:0]	rs2_data,			//op2 in rs2
//  input	fetched,
  
//  input	[`REG_DATA_LEN-1:0] csr_read_data,		//从CSR中读出的数据，写入rd，应该放在执行阶段
  
  output	reg rs1_r_ena,					//rs1 read enable
  output	[4:0]	rs1_r_addr,			//rs1 read addr
  output	reg rs2_r_ena,					//rs2 read enable
  output	[4:0]	rs2_r_addr,			//rs2 read addr
  output	reg rd_w_ena,					//rd write enable
  output	[4:0]	rd_w_addr,			//rd write addr
  
  output	csr_imm_ena,							//csr立即数使能
  output	[`REG_DATA_LEN-1:0]	csr_imm,						//csr立即数
  
  output	[5:0]	inst_type,			//6 inst type--one hot code			
  output	[7:0]	inst_opcode,		//自定义8位操作码，{func3[2:0],opcode[6:2]}
  output	reg [`REG_DATA_LEN-1:0]	op1,			//64bit op1 data
  output	reg [`REG_DATA_LEN-1:0]	op2,				//64bit op2 data
  output	reg	[`REG_DATA_LEN-1:0]	extend_imm,				//立即数符号扩展
  output	[6:0]	funct7
);

/*----------------------distribute the 32-bit inst code-----------------------*/
wire	[6:0]	opcode;
wire	[4:0]	rd_or_imm;
wire	[2:0]	func_or_imm;
wire	[4:0]	rs1_or_imm;
wire	[4:0]	rs2_or_imm;
wire	[6:0]	imm;

assign	opcode = inst[6:0];
assign	rd_or_imm = inst[11:7];
assign	func_or_imm = inst[14:12];
assign	rs1_or_imm = inst[19:15];
assign	rs2_or_imm = inst[24:20];
assign	imm = inst[31:25];
assign	funct7 = imm;

/*------------------obtain inst_opcode and identify the inst-------------------*/
assign	inst_opcode = {func_or_imm , opcode[6:2]};
//I-type
wire	inst_addi;
wire	inst_ori;
wire	inst_andi;
wire	inst_slli;		//立即数逻辑左移
wire	inst_slti;		//小于立即数则置位有符号比较
wire	inst_sltiu;		//小于立即数则置位，无符号数
wire	inst_srai_srli;		//立即数算术右移
wire	inst_xori;		//立即数异或
wire	inst_lb;		//字节加载
wire	inst_lbu;		//无符号字节加载
wire	inst_lh;		//半字加载
wire	inst_lhu;		//无符号半字加载
wire	inst_lw;		//字加载
wire	inst_lwu;		//无符号字加载
wire	inst_ld;		//双字加载
wire	inst_jalr;		//寄存器链接跳转
wire	inst_addiw;		//加立即数字
wire	inst_slliw;		//立即数逻辑左移字
wire	inst_srliw_sraiw;	//立即数逻辑右移字，立即数算术右移字
//CSR
wire	inst_csrrw;		//原子性交换CSR
wire	inst_csrrs;		//atomic read and set bits
wire	inst_csrrc;		//atomic read and clear bits
wire	inst_csrrwi;
wire	inst_csrrsi;
wire	inst_csrrci;

assign	inst_addi = (inst_opcode == 8'b000_00100) ? 1'b1 : 1'b0;
assign	inst_ori = (inst_opcode == 8'b110_00100) ? 1'b1 : 1'b0;
assign	inst_andi = (inst_opcode == 8'b111_00100) ? 1'b1 : 1'b0;
assign	inst_slli = (inst_opcode == 8'b001_00100) ? 1'b1 : 1'b0;
assign	inst_slti = (inst_opcode == 8'b010_00100) ? 1'b1 : 1'b0;
assign	inst_sltiu = (inst_opcode == 8'b011_00100) ? 1'b1 : 1'b0;
assign	inst_srai_srli = (inst_opcode == 8'b101_00100) ? 1'b1 : 1'b0;
assign	inst_xori = (inst_opcode == 8'b100_00100) ? 1'b1 : 1'b0;
assign	inst_lb = (inst_opcode == 8'b000_00000) ? 1'b1 : 1'b0;
assign	inst_lbu = (inst_opcode == 8'b100_00000) ? 1'b1 : 1'b0;
assign	inst_lh = (inst_opcode == 8'b001_00000) ? 1'b1 : 1'b0;
assign	inst_lhu = (inst_opcode == 8'b101_00000) ? 1'b1 : 1'b0;
assign	inst_lw = (inst_opcode == 8'b010_00000) ? 1'b1 : 1'b0;
assign	inst_lwu = (inst_opcode == 8'b110_00000) ? 1'b1 : 1'b0;
assign	inst_jalr = (inst_opcode == 8'b000_11001) ? 1'b1 :1'b0;
assign	inst_ld = (inst_opcode == 8'b011_00000) ? 1'b1 : 1'b0;
assign	inst_addiw = (inst_opcode == 8'b000_00110) ? 1'b1 : 1'b0;
assign	inst_slliw = (inst_opcode == 8'b001_00110) ? 1'b1 : 1'b0;
assign	inst_srliw_sraiw = (inst_opcode == 8'b101_00110) ? 1'b1 : 1'b0;
assign	inst_csrrw = (inst_opcode == 8'b001_11100) ? 1'b1 : 1'b0;
assign	inst_csrrs = (inst_opcode == 8'b010_11100) ? 1'b1 : 1'b0;
assign	inst_csrrc = (inst_opcode == 8'b011_11100) ? 1'b1 : 1'b0;
assign	inst_csrrwi = (inst_opcode == 8'b101_11100) ? 1'b1 : 1'b0;
assign	inst_csrrsi = (inst_opcode == 8'b110_11100) ? 1'b1 : 1'b0;
assign	inst_csrrci = (inst_opcode == 8'b111_11100) ? 1'b1 : 1'b0;
//R-type
wire	inst_add_sub;
wire	inst_and;
wire	inst_or;
wire	inst_xor;
wire	inst_srl_sra;		//逻辑右移
wire	inst_sll;		//逻辑左移
wire	inst_slt;		//小于则置位
wire	inst_sltu;		//无符号小于则置位
wire	inst_addw_subw;		//加字
wire	inst_sllw;		//逻辑左移字
wire	inst_sraw_srlw;		//逻辑右移字
//wire	inst_sra;		//算术右移
//wire	inst_sub;

assign	inst_add_sub = (inst_opcode == 8'b000_01100) ? 1'b1 : 1'b0;
assign	inst_and = (inst_opcode == 8'b111_01100) ? 1'b1 : 1'b0;
assign	inst_or = (inst_opcode == 8'b110_01100) ? 1'b1 : 1'b0;
assign	inst_xor = (inst_opcode == 8'b100_01100) ? 1'b1 : 1'b0;
assign	inst_srl_sra = (inst_opcode == 8'b101_01100) ? 1'b1 : 1'b0;
assign	inst_sll = (inst_opcode == 8'b001_01100) ? 1'b1 : 1'b0;
assign	inst_slt = (inst_opcode == 8'b010_01100) ? 1'b1 : 1'b0;
assign	inst_sltu = (inst_opcode == 8'b011_01100) ? 1'b1 : 1'b0;
assign	inst_addw_subw = (inst_opcode == 8'b000_01110) ? 1'b1 : 1'b0;
assign	inst_sllw = (inst_opcode == 8'b001_01110) ? 1'b1 : 1'b0;
assign	inst_sraw_srlw = (inst_opcode == 8'b101_01110) ? 1'b1 : 1'b0;
//assign	inst_sra = (inst_opcode == 8'b101_01100) ? 1'b1 : 1'b0;

//S-type
wire	inst_sb;		//字节存储
wire	inst_sh;		//半字存储
wire	inst_sw;		//字存储
wire	inst_sd;		//双字存储
assign	inst_sb = (inst_opcode == 8'b000_01000) ? 1'b1 : 1'b0;
assign	inst_sh = (inst_opcode == 8'b001_01000) ? 1'b1 : 1'b0;
assign	inst_sw = (inst_opcode == 8'b010_01000) ? 1'b1 : 1'b0;
assign	inst_sd = (inst_opcode == 8'b011_01000) ? 1'b1 : 1'b0;

//B-type
wire	inst_beq;		//branch if equal
wire	inst_bne;		//branch if not equal
wire	inst_blt;		//branch if lower than
wire	inst_bge;		//branch if greater and equal
wire	inst_bltu;		//无符号，branch if lower than
wire	inst_bgeu;		//无符号,branch if greater and equal
assign	inst_beq = (inst_opcode == 8'b000_11000) ? 1'b1 : 1'b0;
assign	inst_bne = (inst_opcode == 8'b001_11000) ? 1'b1 : 1'b0;
assign	inst_blt = (inst_opcode == 8'b100_11000) ? 1'b1 : 1'b0;
assign	inst_bge = (inst_opcode == 8'b101_11000) ? 1'b1 : 1'b0;
assign	inst_bltu = (inst_opcode == 8'b110_11000) ? 1'b1 : 1'b0;
assign	inst_bgeu = (inst_opcode == 8'b111_11000) ? 1'b1 : 1'b0;


//U-type
wire	inst_lui;		//高位立即数加载
wire	inst_auipc;		//x[rd] = pc + (imm<<12)
assign	inst_lui = (opcode[6:2] == 5'b01101) ? 1'b1 : 1'b0;
assign	inst_auipc = (opcode[6:2] == 5'b00101) ? 1'b1 : 1'b0;

//J-type
wire	inst_jal;		//jump and link
assign	inst_jal = (opcode[6:2] == 5'b11011) ? 1'b1 : 1'b0;


//ecall
wire	inst_ecall;
assign	inst_ecall = (inst_opcode == 8'b000_11100) ? 
					((funct7 == 7'b0000000) ? 1'b1 : 1'b0) : 1'b0;
wire	inst_mret;
assign	inst_mret = (inst_opcode == 8'b000_11100) ?
					((funct7 == 7'b0011000) ? 1'b1 : 1'b0) : 1'b0;

/*-------------------------------obtain the inst_type-----------------------------*/
//R-type = 00_0001; I-type = 00_0010; S-type = 00_0100;
//B-type = 00_1000; U-type = 01_0000; J-type = 10_0000;
assign inst_type[0] = (rst == 1'b1) ? 1'b0 : (inst_add_sub | inst_and | inst_or | inst_xor
											| inst_srl_sra | inst_sll | inst_slt | inst_sltu
											| inst_addw_subw | inst_sllw | inst_sraw_srlw);
assign inst_type[1] = (rst == 1'b1) ? 1'b0 : (inst_addi | inst_ori | inst_andi | inst_slli 
											| inst_slti | inst_sltiu | inst_srai_srli | inst_xori
											| inst_lb | inst_lbu | inst_lh | inst_lhu
											| inst_lw | inst_lwu | inst_jalr | inst_ld
											| inst_addiw | inst_slliw | inst_srliw_sraiw
											| inst_csrrw | inst_csrrs | inst_csrrc 
											| inst_csrrwi | inst_csrrsi | inst_csrrci);
assign inst_type[2] = (rst == 1'b1) ? 1'b0 : (inst_sb | inst_sh | inst_sw | inst_sd);
assign inst_type[3] = (rst == 1'b1) ? 1'b0 : (inst_beq | inst_bne | inst_blt | inst_bge | inst_bltu | inst_bgeu);
assign inst_type[4] = (rst == 1'b1) ? 1'b0 : (inst_lui | inst_auipc);
assign inst_type[5] = (rst == 1'b1) ? 1'b0 : inst_jal;


//wire	csr_imm_ena;							//csr立即数
//wire	[`REG_DATA_LEN-1:0]	csr_imm;
assign	csr_imm_ena = inst_csrrwi | inst_csrrsi | inst_csrrci; 
assign	csr_imm = csr_imm_ena ? {{(`REG_DATA_LEN-5){1'b0}},rs1_or_imm} : 64'd0;

/*-----------define the reg enable signal and addr,obtain the operands---------------*/
always @(*)
  begin
    case(inst_type)
      6'b000001:      //R-type
        begin
			rs2_r_ena = (rst == 1'b1) ? 1'b0 : 1'b1;
			rs1_r_ena = (rst == 1'b1) ? 1'b0 : 1'b1;
			rd_w_ena = (rst == 1'b1) ? 1'b0 : 1'b1;
			
			op2 = (rst == 1'b1) ? {`REG_DATA_LEN{1'b0}} : rs2_data;
			op1 = (rst == 1'b1) ? {`REG_DATA_LEN{1'b0}} : rs1_data;
			extend_imm = {`REG_DATA_LEN{1'b0}};

        end
      6'b000010:      //I-type
        begin
			rs2_r_ena = 1'b0;
			rs1_r_ena = (rst == 1'b1) ? 1'b0 : (inst_addi | inst_ori | inst_andi | inst_slli 
											| inst_slti | inst_sltiu | inst_srai_srli | inst_xori
											| inst_lb | inst_lbu | inst_lh | inst_lhu
											| inst_lw | inst_lwu | inst_jalr | inst_ld
											| inst_addiw | inst_slliw | inst_srliw_sraiw
											| inst_csrrw | inst_csrrs | inst_csrrc);
			rd_w_ena = (rst == 1'b1) ? 1'b0 : 1'b1;
			
			op2 = (rst == 1'b1) ? {`REG_DATA_LEN{1'b0}} : {{(`REG_DATA_LEN-12){imm[6]}} , imm[6:0] , rs2_or_imm[4:0]};
			op1 = (rst == 1'b1) ? {`REG_DATA_LEN{1'b0}} : rs1_data;
			extend_imm = (rst == 1'b1) ? {`REG_DATA_LEN{1'b0}} : {{(`REG_DATA_LEN-12){imm[6]}} , imm[6:0] , rs2_or_imm[4:0]};

        end
      6'b000100: 		//S-type
        begin
			rs2_r_ena = (rst == 1'b1) ? 1'b0 : 1'b1;
			rs1_r_ena = (rst == 1'b1) ? 1'b0 : 1'b1;
			rd_w_ena = 1'b0;
			
			op2 = (rst == 1'b1) ? {`REG_DATA_LEN{1'b0}} : rs2_data;
			op1 = (rst == 1'b1) ? {`REG_DATA_LEN{1'b0}} : rs1_data;
			extend_imm = (rst == 1'b1) ? {`REG_DATA_LEN{1'b0}} : {{(`REG_DATA_LEN-12){imm[6]}},imm[6:0],rd_or_imm[4:0]};

        end
      6'b001000: 		//B-type
        begin
			rs2_r_ena = (rst == 1'b1) ? 1'b0 : 1'b1;
			rs1_r_ena = (rst == 1'b1) ? 1'b0 : 1'b1;
			rd_w_ena = 1'b0;
			
			op2 = (rst == 1'b1) ? {`REG_DATA_LEN{1'b0}} : rs2_data;
			op1 = (rst == 1'b1) ? {`REG_DATA_LEN{1'b0}} : rs1_data;
			extend_imm = (rst == 1'b1) ? {`REG_DATA_LEN{1'b0}} : {{(`REG_DATA_LEN-13){imm[6]}},imm[6],rd_or_imm[0],imm[5:0],rd_or_imm[4:1],1'b0};
        end
      6'b010000: 		//U-type
        begin
			rs2_r_ena = 1'b0;
			rs1_r_ena = 1'b0;
			rd_w_ena = (rst == 1'b1) ? 1'b0 : 1'b1;
			
			op2 = {`REG_DATA_LEN{1'b0}};
			op1 = {`REG_DATA_LEN{1'b0}};
			extend_imm = {{(`REG_DATA_LEN-32){imm[6]}},imm[6:0],rs2_or_imm[4:0],rs1_or_imm[4:0],func_or_imm[2:0],12'd0};
        end
      6'b100000:		//J-type
        begin
			rs2_r_ena = 1'b0;
			rs1_r_ena = 1'b0;
			rd_w_ena = (rst == 1'b1) ? 1'b0 : 1'b1; 
			
			op2 = {`REG_DATA_LEN{1'b0}};
			op1 = {`REG_DATA_LEN{1'b0}};
			extend_imm = {{(`REG_DATA_LEN-21){imm[6]}},imm[6],rs1_or_imm[4:0],func_or_imm[2:0],rs2_or_imm[0],imm[5:0],rs2_or_imm[4:1],1'b0};
        end		
      default:
		begin
			rs2_r_ena = 1'b0;
			rs1_r_ena = 1'b0;
			rd_w_ena = 1'b0;
			
			op2 = {`REG_DATA_LEN{1'b0}};
			op1 = {`REG_DATA_LEN{1'b0}};
			extend_imm = {`REG_DATA_LEN{1'b0}};

		end
	endcase
  end

/*-----------------------------define the reg enable signal and addr-----------------------*/
//assign rs2_r_ena = (rst == 1'b1) ? 1'b0 : ~(inst_type[1] | inst_type[4] | inst_type[5]);
//assign rs1_r_ena = (rst == 1'b1) ? 1'b0 : ~(inst_type[4] | inst_type[5]);
//assign rd_w_ena = (rst == 1'b1) ? 1'b0 : ~(inst_type[2] | inst_type[3]);


assign rs2_r_addr = (rs2_r_ena == 1'b1) ? rs2_or_imm : 5'd0;
assign rs1_r_addr = (rs1_r_ena == 1'b1) ? rs1_or_imm : 5'd0;
assign rd_w_addr = (rd_w_ena == 1'b1) ? rd_or_imm : 5'd0;

/*----------------------------obtain the operands------------------------------*/
//assign op2 = (inst_type[1]) ? {{52{imm[6]}} , imm[6:0] , rs2_or_imm[4:0]} : 0;
//assign op1 = (inst_type[1]) ? rs1_data : 0;


endmodule

